volatile和atomic(如何实现一个线程安全的类)

您所在的位置:网站首页 volatile 线程安全 volatile和atomic(如何实现一个线程安全的类)

volatile和atomic(如何实现一个线程安全的类)

2022-06-08 11:34| 来源: 网络整理| 查看: 265

AtomicInteger类位于concurrent.atomic包下,其主要用于支持int或Integer类型上的原子操作。原子可以保证线程安全。因此,AtomicInteger类经常被用作线程安全计数器,其功能是int和Integer无法替代的。

原子操作意味着一个操作不能被分割或重新排序,执行的结果要么成功,要么失败。这里的操作可以是一个或多个指令。

AtomicInteger类也继承了Number类。Number类是一个抽象类,也是所有可以转换为基本类型的数值类的父类。它的主要功能是标准化数字数据类型的转换。

路径:\ Java \ util \并发\原子\原子integer.java

AtomicInteger类成员变量

AtomicInteger类方法列表

00-1010首先,常规成员变量,包括序列化id和值等。需要注意的是,这里的value属性由volatile关键字修饰,这是定义多线程关键资源的常规方法,表示该属性对多线程具有可见性,禁止指令重排序。

在当前的Java内存模型下,线程可以将变量保存在本地内存(如机器寄存器)中,而不是直接在主内存中读写。这可能会导致一个线程修改主内存中的变量值,而另一个线程继续使用其变量值在寄存器中的副本,从而导致数据不一致。

要解决这个问题,需要声明一个变量为volatile,这就向JVM表明这个变量是不稳定的,每次使用都要在主存中读取。

除了常规成员变量之外,AtomicInteger类还定义了一个不安全变量,用于在直接内存上操作。不安全类位于sun.misc包下,用于操作直接内存。它提供的大多数方法都是本机的。

此外,AtomicInteger类定义了一个静态代码块来获取内存中value属性的偏移量。

静态代码块随着类的加载而执行,并且只执行一次,其原理类似于static关键字。类中代码块的执行顺序是:静态代码块-构造代码块-构造函数。

一、成员变量 AtomicInteger的构造器相对简单。您可以直接使用默认构造函数获取初始值0或值,或者通过参数为其赋值。

二、构造器如果要在初始化后赋值,需要使用set()方法。AtomicInteger提供了两套。

三、set()和lazySet() set()方法可以完成直接赋值。

1、set() >2、lazySet()

lazySet()方法实现了对value的非volatile赋值,通过调用unsafe.putOrderedInt()方法,直接向固定偏移量的内存上写入数据,但不使其对其他线程立刻可见(putOrderedInt()是putIntVolatile()的延迟实现)。

lazySet()方法存在的意义是在某些不需要volatile的场景下,通过延迟赋值提高程序运行的效率。这个方法很少被上层调用者使用。

四、get()

想要获取value的值就需要使用get()方法,AtomicInteger除了提供基本的get()方法之外,还提供了getAndSet(),getAndIncrement(),getAndDecrement(),getAndAdd(),getAndUpdate()和getAndAccumulate()等方法。

1、get()

2、getAndSet()

getAndSet()方法实际上调用getAndSetInt()方法,它的底层实现逻辑是利用getIntVolatile()方法获取value后进行的自旋CAS操作。

其中unsafe.getAndSetInt()方法的源码如下所示,这两个方法都是native方法。

3、getAndIncrement(),getAndDecrement()和getAndAdd()

这两个方法实现的原理和getAndSet()方法基本是一样的,只是将get出来的value加1或减1了而已。

4、getAndUpdate()和getAndAccumulate()

getAndUpdate()和getAndAccumulate()分别以函数式编程接口IntUnaryOperator和IntBinaryOperator为入参,实现AtomicInteger的自定义变换。用户可以自定义一个函数,让value按函数计算结果递增,也可以定义两个可以互相翻转的int,使value交替变换。

可以看到,两个方法的核心都是compareAndSet(),它的源码为:

与之相对的是weakCompareAndSet()方法,它是一个少数情况下compareAndSet()方法的替代。JDK8及以前,这两个方法的实现代码完全一样,而在JDK9之后,weakCompareAndSet()方法增加了@HotSpotIntrinsicCandidate注解。

这两个方法的具体区别我还没有搞清楚,只能先给大家两个参考链接了,虽然我个人认为第一个链接里讲的未必正确...(链接被平台禁了,麻烦有兴趣的朋友自行搜索吧)

五、其他1、toString()

2、其他继承自Number类的方法

以上就是我在阅读AtomicInteger类源码时留下的笔记,存在些许不足之处,欢迎大家进行交流讨论。如果觉得头条看代码不够爽,也欢迎大家来我的简书浏览相关文章(https://www.jianshu.com/p/daa4e062746a)。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3